package com.sinszm.common.util;

import com.sinszm.common.exception.ApiException;
import org.dom4j.*;
import org.dom4j.dom.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.nutz.lang.Files;
import org.nutz.lang.Xmls;
import org.nutz.lang.util.NutMap;
import org.springframework.lang.NonNull;
import org.springframework.util.StringUtils;

import java.io.*;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.SortedMap;
import java.util.TreeMap;

import static com.sinszm.common.exception.SystemApiError.*;

/**
 * XML 操作工具
 *
 * @author chenjianbo
 */
public final class XmlUtils {

    private static final String HEAD = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";

    /**
     * 基本的XML解析
     *
     * @param xml   xml内容
     * @return      结果
     */
    public static SortedMap<String, String> basicXmlToMap(String xml) {
        return basicXmlToMap(xml, "UTF-8");
    }

    /**
     * 基本的XML解析
     *
     * @param xml           xml内容
     * @param charsetName   字符编码
     * @return              结果
     */
    public static SortedMap<String, String> basicXmlToMap(String xml, String charsetName) {
        if (StringUtils.isEmpty(xml)) {
            throw new ApiException(XML_ERROR_01);
        }
        SortedMap<String, String> map = new TreeMap<>();
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(
                    new ByteArrayInputStream(
                            xml.getBytes(Charset.forName(charsetName))
                    )
            );
            Element root = document.getRootElement();
            for (Iterator<Element> it = root.elementIterator(); it.hasNext(); ) {
                Element element = it.next();
                map.put(element.getName(), element.getXPathResult(0).getText());
            }
            return map;
        } catch (DocumentException e) {
            e.printStackTrace(System.err);
            throw new ApiException(XML_ERROR_02);
        }
    }

    /**
     * 基本的XML生成
     *
     * @param map   数据
     * @return      结果
     */
    public static String basicMapToXml(SortedMap<String, String> map) {
        return basicMapToXml(map, "UTF-8");
    }

    /**
     * 基本的XML生成
     *
     * @param map           数据
     * @param charsetName   字符编码
     * @return              结果
     */
    public static String basicMapToXml(SortedMap<String, String> map, String charsetName) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        return HEAD +
                element(map, charsetName).asXML();
    }

    /**
     * 带格式的XML生成
     *
     * @param map   数据
     * @return      结果
     */
    public static String basicMapToXmlNice(SortedMap<String, String> map) {
        return basicMapToXmlNice(map, "UTF-8");
    }

    /**
     * 带格式的XML生成
     *
     * @param map           数据
     * @param charsetName   字符编码
     * @return              结果
     */
    public static String basicMapToXmlNice(SortedMap<String, String> map, String charsetName) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        Element elt = element(map, charsetName);
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setIndent("    ");
        format.setEncoding(charsetName);
        try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
            XMLWriter writer = new XMLWriter(out, format);
            writer.write(elt);
            writer.flush();
            writer.close();
            return HEAD +
                    new String(out.toByteArray(), charsetName);
        } catch (IOException e) {
            e.printStackTrace(System.err);
            throw new ApiException(XML_ERROR_03);
        }
    }

    private static Element element(@NonNull SortedMap<String, String> map, @NonNull String charsetName) {
        Document target = DocumentHelper.createDocument(new DOMElement("xml"));
        target.setXMLEncoding(charsetName);
        Element element = target.getRootElement();
        map.forEach((k, v) -> {
            Element node = element.addElement(k);
            node.add(new DOMCDATA(v));
        });
        return element;
    }

    /**
     * 基本的XML文件生成
     *
     * @param map         数据
     * @param charsetName 字符编码
     * @param file        目标文件
     */
    public static void basicMapToFile(SortedMap<String, String> map, String charsetName, File file) {
        if (file == null
                || file.isDirectory()
                || file.getPath().lastIndexOf(".xml") < 0) {
            throw new ApiException(XML_ERROR_04);
        }
        Files.write(
                file,
                basicMapToXmlNice(map, charsetName)
        );
    }

    /**
     * Xml转Map
     *
     * @param xml   数据
     * @return      结果
     */
    public static NutMap xmlToMap(String xml) {
        if (StringUtils.isEmpty(xml)) {
            throw new ApiException(XML_ERROR_01);
        }
        return Xmls.xmlToMap(xml);
    }

    /**
     * Map转Xml
     *
     * @param map   数据
     * @return      结果
     */
    public static String mapToXml(SortedMap<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        return Xmls.mapToXml(map);
    }

}
